package area

import (
	"gddgame.cc/galaxy/common/dsl/game"
	. "gddgame.cc/galaxy/common/dsl/web"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/orm"
)

type AreaData struct {
	env            *game.Environment
	areaSmallModel *orm.Model
	areaWorldModel *orm.Model
}

func GetAreaData(env *game.Environment) (*AreaData, error) {
	var err error
	data := &AreaData{env: env}
	if data.areaSmallModel, err = env.GetModel(AreaSmallName); err != nil {
		return nil, err
	}
	if data.areaWorldModel, err = env.GetModel(AreaWorldName); err != nil {
		return nil, err
	}

	return data, nil
}

func (data *AreaData) LoadSmall(identity string) (int, []byte, error) {
	var err error
	var ok bool
	var area AreaWorld

	areaI, err := data.env.CacheString("small/identity/"+utils.ToString(identity), func() (string, error) {
		if ok, err = data.areaWorldModel.Query().
			Where("=", "identity", identity).One(&area); !ok {
			return "", EmptyExceptionDetail("AREA_NOEXIST", err)
		}
		return utils.ToString(area.Id), nil
	})
	if area.Id == 0 {
		if err := data.env.Cache("small/"+areaI, &area, func() error {
			if ok, err = data.areaWorldModel.PK(areaI).One(&area); !ok {
				return EmptyExceptionDetail("AREA_NOEXIST", err)
			}
			return nil
		}); err != nil {
			return 0, nil, nil
		}
	} else {
		_ = data.env.Cache("small/"+utils.ToString(areaI), &area, func() error {
			return nil
		})
	}
	return area.Id, area.Content, nil
}

func (data *AreaData) UpdateSmall(id int, content []byte) error {
	if err := data.env.SingleClean("small/"+utils.ToString(id), func() error {
		if _, err := data.areaSmallModel.PK(id).Update(map[string]interface{}{
			"content": content,
		}); err != nil {
			return SystemExceptionDetail("更新小场景失败", err)
		}
		return nil
	}, false); err != nil {
		return err
	}

	return nil
}

func (data *AreaData) LoadWorld(identity string, location []byte) (int, []byte, error) {
	var err error
	var ok bool
	var area AreaWorld

	// 只缓存open与userId的关系
	areaI, err := data.env.CacheString("world/identity/"+identity+"/"+utils.ToString(location), func() (string, error) {
		if ok, err = data.areaWorldModel.Query().
			Where("=", "identity", identity).
			Where("=", "location", location).One(&area); !ok {
			return "", EmptyExceptionDetail("AREA_NOEXIST", err)
		}
		return utils.ToString(area.Id), nil
	})
	if area.Id == 0 {
		if err := data.env.Cache("world/"+areaI, &area, func() error {
			if ok, err = data.areaWorldModel.PK(areaI).One(&area); !ok {
				return EmptyExceptionDetail("AREA_NOEXIST", err)
			}
			return nil
		}); err != nil {
			return 0, nil, nil
		}
	} else {
		_ = data.env.Cache("world/"+areaI, &area, func() error {
			return nil
		})
	}
	return area.Id, area.Content, nil
}

func (data *AreaData) UpdateWorld(id int, content []byte) error {
	if err := data.env.SingleClean("world/"+utils.ToString(id), func() error {
		if _, err := data.areaWorldModel.PK(id).Update(map[string]interface{}{
			"content": content,
		}); err != nil {
			return SystemExceptionDetail("更新大场景失败", err)
		}
		return nil
	}, false); err != nil {
		return err
	}

	return nil
}

func (data *AreaData) UpdateLocation(openId string, areaId string, location []byte) error {
	return data.env.UpdateOpenStore(openId, "area/"+areaId, location)
}

func (data *AreaData) GetLocation(openId string, areaId string) []byte {
	v, err := data.env.GetOpenStore(openId, "area/"+areaId)
	if err != nil {
		return nil
	}
	return utils.ToBytes(v)
}
